﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI;
using blackhouse.WebNemo.Business.Groups;
using blackhouse.WebNemo.Web.Validators;
using System.Xml.Serialization;
using System.IO;
using blackhouse.WebNemo.Web.Controls;

namespace blackhouse.WebNemo.Web.Controls {
    internal class EditController {

        #region Fields

        private Label lblName;
        private Label lblDescription;
        private Panel pnlEdit;
        private Panel pnlValidators;
        private Panel pnlHolder;
        private HyperLink lnkAddTranslate;
        private Control parentControl;
        private List<GroupColumn> columns;
        private GroupRecord record;

        private EditRecordValue editControl;

        #endregion

        #region Properties

        public bool IsPopulated {
            get;
            private set;
        }

        public VirtualColumn VirtualColumn {
            get;
            private set;
        }

        #endregion

        #region Constructors

        public EditController(GroupColumn column, GroupRecord record) {
            this.columns = new List<GroupColumn>(new GroupColumn[] { column });
            this.record = record;
        }

        public EditController(VirtualColumn virtualColumn, GroupRecord record) {
            this.VirtualColumn = virtualColumn;
            this.columns = new List<GroupColumn>();
            this.record = record;
        }

        #endregion

        #region Methods

        private void PopulateName() {
            if (lblName != null) {
                lblName.Text = columns.Name;
                if (!columns.AllowNull)
                    lblName.Text += " " + this.GetRequiredIcon();
                lblName.Text += ":";
                lblName.CssClass += " record-edit-i-n-" + columns.ColumnId;
            }
        }

        private EditRecordValue GetEditControl() {
            EditRecordValue ec = null;
            if (!string.IsNullOrEmpty(columns.CustomEditControl)) {
                ec = this.GetEditCustomControl(columns.CustomEditControl);
                if (ec != null) {
                    IConfigurableEditRecord ecc = ec as IConfigurableEditRecord;
                    if (ecc != null)
                        ecc.Config = columns.GetCustomEditControlConfiguration();
                }
            }

            if (ec == null) {
                if (columns.ColumnType == FieldType.ValueField || columns.ColumnType == FieldType.DateField || columns.ColumnType == FieldType.DateTimeField) {
                    ec = new InlineEditRecordValue();
                }
                if (columns.ColumnType == FieldType.OneReference || columns.ColumnType == FieldType.ManyReference)
                    ec = new ReferenceEditRecordValue();

                if (columns.ColumnType == FieldType.FileField)
                    ec = new FileEditRecordValue();
            }

            return ec;
        }

        private bool PopulateEditControl() {
            if (pnlEdit != null) {

                this.editControl = this.GetEditControl();
                if (this.editControl == null)
                    this.parentControl.Visible = false;
                else {
                    pnlEdit.Controls.Add(editControl);
                    editControl.SetControl(columns, record);
                }
            }
            return this.editControl != null;
        }

        private void PopulateTranslateLink() {
            if (lnkAddTranslate != null
                && columns.ColumnType == FieldType.ValueField
                && columns.DataType == typeof(string)) {
                lnkAddTranslate.Visible = true;
                lnkAddTranslate.NavigateUrl = NemoUrlUtils.GetStartUrl() + "EditTranslate.aspx?groupId=" + record.BelongsToGroupId + "&fieldId=" + columns.ColumnId + "&recordId=" + record.RecordId + "&mod=popup";
            }
        }

        public void Populate(Label lblName, Label lblDescription, Panel pnlEdit, Panel pnlValidators, Panel pnlHolder, HyperLink lnkAddTranslate, Control parentControl) {
            this.lblName = lblName;
            this.lblDescription = lblDescription;
            this.pnlEdit = pnlEdit;
            this.pnlValidators = pnlValidators;
            this.pnlHolder = pnlHolder;
            this.lnkAddTranslate = lnkAddTranslate;
            this.parentControl = parentControl;

            this.PopulateControl();
        }

        private void PopulateControl() {
            if (columns == null || record == null) {
                this.parentControl.Visible = false;
                return;
            }

            this.PopulateName();
            if (!this.PopulateEditControl())
                return;
            this.PopulateTranslateLink();

            if (pnlHolder != null) {
                if (editControl.DisplayInline)
                    pnlHolder.CssClass += " record-edit-idi";
            }

            this.PopulateValidators();
            this.PopulateDescription();

            this.IsPopulated = this.parentControl.Visible && this.editControl != null;

        }

        private void PopulateDescription() {
            if (lblDescription != null && !string.IsNullOrEmpty(columns.Description)) {
                lblDescription.Visible = true;
                lblDescription.Text = columns.Description;
            }
        }

        private void PopulateValidators() {
            if (pnlValidators != null && this.editControl != null) {
                BaseValidator[] validators = editControl.GetValidators();
                BaseValidator[] customValidators = this.GetCustomValidators();
                this.PopulateValidators(validators);
                this.PopulateValidators(customValidators);
            }
        }

        private BaseValidator[] GetCustomValidators() {
            CustomValidatorInfo[] vals = this.columns.CustomValidators;
            List<BaseValidator> validators = new List<BaseValidator>();
            foreach (CustomValidatorInfo item in vals) {
                IValidatorSource s = this.ReadValidator(item);
                if (s != null) {
                    s.Set(this.record, this.columns, this.editControl);
                    validators.AddRange(s.GetValidators());
                }
            }
            return validators.ToArray();
        }

        private IValidatorSource ReadValidator(CustomValidatorInfo data) {
            Type t = Type.GetType(data.InstanceClass, false, true);
            if (t == null) return null;

            XmlSerializer xml = new XmlSerializer(t);
            IValidatorSource s = xml.Deserialize(new StringReader(data.XmlConfiguration)) as IValidatorSource;
            return s;
        }

        private void PopulateValidators(BaseValidator[] validators) {
            foreach (BaseValidator validator in validators) {
                validator.Display = ValidatorDisplay.Dynamic;
                validator.EnableClientScript = true;
                validator.SetFocusOnError = true;
                pnlValidators.Controls.Add(validator);
                pnlValidators.CssClass = "error-line";
            }
        }

        private string GetRequiredIcon() {
            return this.GetIconCode("Pole jest wymagane!", "required");
        }

        private string GetExtraIcon(string text) {
            return this.GetIconCode(text, "extra");
        }

        private string GetIconCode(string text, string icon) {
            return "<a title=\"" + text + "\" class=\"ui-icon ui-icon-" + icon + "\">" + text + "</a>";
        }

        private EditRecordValue GetEditCustomControl(string control) {
            Type t = Type.GetType(control, false);
            if (t != null)
                return Activator.CreateInstance(t) as EditRecordValue;
            else
                return null;
        }

        public void SaveInRecord() {
            if (editControl != null)
                this.editControl.SaveInRecord();
        }

        public string GetValue() {
            if (editControl != null)
                return this.editControl.GetValue();
            else
                return "";
        }

        public void ReSetValue(object value) {
            if (editControl != null)
                this.editControl.ReSetValue(value);
        }

        public void AddColumn(GroupColumn column) {
            this.columns.Add(column);
        }

        #endregion

    }
}